//  Copyright (c) 2010 Mahesh Sharma,Matt MacDonald
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.

package org.prx.prp.utility;

import org.prx.prp.utility.DatabaseHelper;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

import android.util.Log;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpHelper {
    private static final String CONTENT_TYPE = "Content-Type";
    private static final int POST_TYPE = 1;
    private static final int GET_TYPE = 2;
    public static final String MIME_FORM_ENCODED = "application/x-www-form-urlencoded";
    public static final String MIME_TEXT_PLAIN = "text/plain";
    public static final String HTTP_RESPONSE = "HTTP_RESPONSE";
    public static final String HTTP_RESPONSE_ERROR = "HTTP_RESPONSE_ERROR";
    private static final DefaultHttpClient client;
    
    static {
        HttpParams params = new BasicHttpParams();
        params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
        params.setParameter(CoreProtocolPNames.USER_AGENT, "Apache-HttpClient/Android");
        params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15000);
        params.setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false);
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
        client = new DefaultHttpClient(cm, params);
    }
   
    private final ResponseHandler<String> responseHandler;
    
    public HttpHelper() {
        this.responseHandler = new BasicResponseHandler();
    }
    
    public String performGet(final String url) {
        return this.performRequest(null, url, null, null, null, null, HttpHelper.GET_TYPE);
    }
    
    public String performGet(final String url, final String user, final String pass, final Map<String, String> additionalHeaders) {
        return this.performRequest(null, url, user, pass, additionalHeaders, null, HttpHelper.GET_TYPE);
    }
    
    public String performPost(final String url, final Map<String, String> params) {
        return this.performRequest(HttpHelper.MIME_FORM_ENCODED, url, null, null, null, params, HttpHelper.POST_TYPE);
    }
    
    public String performPost(final String url, final String user, final String pass, final Map<String, String> additionalHeaders, final Map<String, String> params) {
        return this.performRequest(HttpHelper.MIME_FORM_ENCODED, url, user, pass, additionalHeaders, params, HttpHelper.POST_TYPE);
    }
    
    public String performPost(final String contentType, final String url, final String user, final String pass, final Map<String, String> additionalHeaders, final Map<String, String> params) {
        return this.performRequest(contentType, url, user, pass, additionalHeaders, params, HttpHelper.POST_TYPE);
    }
    
    private String performRequest(final String contentType, final String url, final String user, final String pass, final Map<String, String> headers, final Map<String, String> params, final int requestType) {
        if ((user != null) && (pass != null)) {
            HttpHelper.client.getCredentialsProvider().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, pass));
        }
        
        final Map<String, String> sendHeaders = new HashMap<String, String>();
        
        if ((headers != null) && (headers.size() > 0)) {
            sendHeaders.putAll(headers);
        }
      
        if (requestType == HttpHelper.POST_TYPE) {
            sendHeaders.put(HttpHelper.CONTENT_TYPE, contentType);
        }
        
        if (sendHeaders.size() > 0) {
            HttpHelper.client.addRequestInterceptor(new HttpRequestInterceptor() {
                	public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
                		for (String key : sendHeaders.keySet()) {
                			if (!request.containsHeader(key)) {
                				request.addHeader(key, sendHeaders.get(key));
                			}
                		}
                	}
                }
            );
        }
      
        HttpRequestBase method = null;
        if (requestType == HttpHelper.POST_TYPE) {
            method = new HttpPost(url);
            List<NameValuePair> nvps = null;
            
            if ((params != null) && (params.size() > 0)) {
                nvps = new ArrayList<NameValuePair>();
                
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
            }
         
            if (nvps != null) {
                try {
                    HttpPost methodPost = (HttpPost) method;
                    methodPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
                } catch (UnsupportedEncodingException e) {
                    Log.d("PRPAND", e.getMessage());
                }
            }
        } else if (requestType == HttpHelper.GET_TYPE) {
            
            String authUrl = url + (url.indexOf('?') != -1 ? '&' : '?') + "key=" + DatabaseHelper.getApiKey();
        
            Log.d("PRPAND", authUrl);
            method = new HttpGet(authUrl);
        }
        
        return this.execute(method);
    }

    private synchronized String execute(final HttpRequestBase method) {
        String response = null;
        try {
            response = HttpHelper.client.execute(method, this.responseHandler);
        } catch (ClientProtocolException e) {
            response = HttpHelper.HTTP_RESPONSE_ERROR + " - " + e.getClass().getSimpleName() + " " + e.getMessage();
        } catch (IOException e) {
            response = HttpHelper.HTTP_RESPONSE_ERROR + " - " + e.getClass().getSimpleName() + " " + e.getMessage();
        }
        return response;
    }
}